﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.SessionState;
using Xenta.Web;
using System.Web.Mvc.Html;

namespace Xenta.Utils
{
    /// <summary>
    /// Contains extension methods.
    /// </summary>
    public static class Extensions
    {
        #region HttpSessionState

        /// <summary>
        /// Persists an object by key in the session state dictionary.
        /// </summary>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        /// <param name="obj">The object.</param>
        public static void PersistObject(this HttpSessionStateBase session, string key, object obj)
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return;
            }
            session[key] = obj;
        }

        /// <summary>
        /// Persists an object by key in the session state dictionary.
        /// </summary>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        /// <param name="obj">The object.</param>
        public static void PersistObject(this HttpSessionState session, string key, object obj)
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return;
            }
            session[key] = obj;
        }

        /// <summary>
        /// Gets the previously persisted object from the session state.
        /// </summary>
        /// <typeparam name="T">The type of object to return.</typeparam>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultObj">The default value to return.</param>
        /// <returns>The object as the type T if it found in state dictionary; otherwise default value;</returns>
        public static T RestoreObject<T>(this HttpSessionStateBase session, string key, T defaultObj = default(T))
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return defaultObj;
            }

            var value = session[key];

            if(value == null)
            {
                return defaultObj;
            }
            return (T)value;
        }

        /// <summary>
        /// Gets the previously persisted object from the session state.
        /// </summary>
        /// <typeparam name="T">The type of object to return.</typeparam>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultObj">The default value to return.</param>
        /// <returns>The object as the type T if it found in state dictionary; otherwise default value;</returns>
        public static T RestoreObject<T>(this HttpSessionState session, string key, T defaultObj = default(T))
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return defaultObj;
            }

            var value = session[key];

            if(value == null)
            {
                return defaultObj;
            }
            return (T)value;
        }

        /// <summary>
        /// Removes the previously persisted object 
        /// from the session state.
        /// </summary>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        public static void RemoveObject(this HttpSessionStateBase session, string key)
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return;
            }
            session.Remove(key);
        }

        /// <summary>
        /// Removes the previously persisted object 
        /// from the session state.
        /// </summary>
        /// <param name="session">The session state.</param>
        /// <param name="key">The key.</param>
        public static void RemoveObject(this HttpSessionState session, string key)
        {
            if(String.IsNullOrWhiteSpace(key))
            {
                return;
            }
            session.Remove(key);
        }

        #endregion

        #region HttpRequest

        /// <summary>
        /// Gets the cookie value from the HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of cookie.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The cookie value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string GetCookie(this HttpRequest request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            var cookie = request.Cookies[name];
            if(cookie == null)
                return defaultValue;
            return cookie.Value;
        }

        /// <summary>
        /// Gets the cookie value as the type T from the HTTP request.
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of cookie.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The cookie value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T GetCookie<T>(this HttpRequest request, string name, T defaultValue = default(T))
        {
            return GetCookie(request, name)
                .ParseAs(defaultValue);
        }

        /// <summary>
        /// Gets the cookie value from the HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of cookie.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The cookie value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string GetCookie(this HttpRequestBase request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            var cookie = request.Cookies[name];
            if(cookie == null)
                return defaultValue;
            return cookie.Value;
        }

        /// <summary>
        /// Gets the cookie value as the type T from the HTTP request.
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of cookie.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The cookie value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T GetCookie<T>(this HttpRequestBase request, string name, T defaultValue = default(T))
        {
            return GetCookie(request, name)
                .ParseAs(defaultValue);
        }

        /// <summary>
        /// Gets the server variable value from the HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of variable.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The variable value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string ServerVariable(this HttpRequest request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            string value = request.ServerVariables[name];
            if(String.IsNullOrWhiteSpace(value))
                return defaultValue;
            return value;
        }

        /// <summary>
        /// Gets the server variable value as the type T from the HTTP request.
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of variable.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The variable value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T ServerVariable<T>(this HttpRequest request, string name, T defaultValue = default(T))
        {
            return ServerVariable(request, name)
                .ParseAs(defaultValue);
        }

        /// <summary>
        /// Gets the server variable value from the HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of variable.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The variable value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string ServerVariable(this HttpRequestBase request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            string value = request.ServerVariables[name];
            if(String.IsNullOrWhiteSpace(value))
                return defaultValue;
            return value;
        }

        /// <summary>
        /// Gets the server variable value as the type T from the HTTP request.
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The name of variable.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The variable value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T ServerVariable<T>(this HttpRequestBase request, string name, T defaultValue = default(T))
        {
            return ServerVariable(request, name)
                .ParseAs(defaultValue);
        }

        /// <summary>
        /// Gets the user host address from HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <returns>The user host addesss.</returns>
        public static string GetUserHostAddress(this HttpRequest request)
        {
            string httpXFwdFor = request.ServerVariable("HTTP_X_FORWARDED_FOR");

            if(!String.IsNullOrWhiteSpace(httpXFwdFor))
            {
                var tmp = httpXFwdFor.Split(',');
                if(tmp.Length != 0)
                    return tmp.First();
            }
            return request.ServerVariable("REMOTE_ADDR");
        }

        /// <summary>
        /// Gets the user host address from HTTP request.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <returns>The user host addesss.</returns>
        public static string GetUserHostAddress(this HttpRequestBase request)
        {
            string httpXFwdFor = request.ServerVariable("HTTP_X_FORWARDED_FOR");

            if(!String.IsNullOrWhiteSpace(httpXFwdFor))
            {
                var tmp = httpXFwdFor.Split(',');
                if(tmp.Length != 0)
                    return tmp.First();
            }
            return request.ServerVariable("REMOTE_ADDR");
        }

        /// <summary>
        /// Gets the query string parameter from HTTP request. 
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The parameter name.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The parameter value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string QueryParam(this HttpRequest request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            string value = request.QueryString[name];
            if(String.IsNullOrWhiteSpace(value))
                return defaultValue;
            return value;
        }

        /// <summary>
        /// Gets the query string parameter as the type T from HTTP request. 
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The parameter name.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The parameter value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T QueryParam<T>(this HttpRequest request, string name, T defaultValue = default(T))
        {
            return QueryParam(request, name)
                .ParseAs(defaultValue);
        }

        /// <summary>
        /// Gets the query string parameter from HTTP request. 
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The parameter name.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The parameter value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static string QueryParam(this HttpRequestBase request, string name, string defaultValue = "")
        {
            if(String.IsNullOrWhiteSpace(name))
                return defaultValue;
            string value = request.QueryString[name];
            if(String.IsNullOrWhiteSpace(value))
                return defaultValue;
            return value;
        }

        /// <summary>
        /// Gets the query string parameter as the type T from HTTP request. 
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="request">The HTTP request.</param>
        /// <param name="name">The parameter name.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The parameter value if it found; otherwise 
        /// the default value.
        /// </returns>
        public static T QueryParam<T>(this HttpRequestBase request, string name, T defaultValue = default(T))
        {
            return QueryParam(request, name)
                .ParseAs(defaultValue);
        }

        #endregion

        #region HttpResponse

        /// <summary>
        /// Set the cookie in HTTP response.
        /// </summary>
        /// <param name="response">The HTTP response</param>
        /// <param name="name">The cookie name.</param>
        /// <param name="value">The cookie value.</param>
        public static void SetCookie(this HttpResponse response, string name, object value)
        {
            if(String.IsNullOrWhiteSpace(name))
                return;
            response.SetCookie(new HttpCookie(name, value.ToString()));
        }

        /// <summary>
        /// Set the cookie in HTTP response.
        /// </summary>
        /// <param name="response">The HTTP response</param>
        /// <param name="name">The cookie name.</param>
        /// <param name="value">The cookie value.</param>
        public static void SetCookie(this HttpResponseBase response, string name, object value)
        {
            if(String.IsNullOrWhiteSpace(name))
                return;
            response.SetCookie(new HttpCookie(name, value.ToString()));
        }

        #endregion

        #region TempDataDictionary

        /// <summary>
        /// Persists an object in the TempData dictionary.
        /// </summary>
        /// <param name="tempData">The TempData dictionary.</param>
        /// <param name="key">The key.</param>
        /// <param name="obj">The object.</param>
        public static void PersistObject(this TempDataDictionary tempData, string key, object obj)
        {
            if(String.IsNullOrWhiteSpace(key))
                return;
            tempData[key] = obj;
        }

        /// <summary>
        /// Gets the previosly persisted object from the TempData dictionary.
        /// </summary>
        /// <typeparam name="T">The type of object.</typeparam>
        /// <param name="tempData">The TempData dictionary.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The object if found; otherwise the default value.
        /// </returns>
        public static T RestoreObject<T>(this TempDataDictionary tempData, string key, T defaultValue = default(T))
        {
            if(String.IsNullOrWhiteSpace(key) ||
                !tempData.ContainsKey(key))
            {
                return defaultValue;
            }
            return (T) tempData[key];
        }

        /// <summary>
        /// Gets previosly persisted status code from the TempData dictionary. 
        /// </summary>
        /// <returns>
        /// The status code, if exists in TempData; otherwise zero.
        /// </returns>
        /// <remarks>
        /// The basic status code usage:
        /// negative value - indicates error,
        /// zero value - indicates no status,
        /// positive value - indicates success
        /// </remarks>
        public static int RestoreStatus(this TempDataDictionary tempData)
        {
            return RestoreObject(tempData, "STATUS_CODE", 0);
        }

        /// <summary>
        /// Persists the status code in the TempData dictionary.
        /// </summary>
        /// <param name="tempData">The TempData dictionary.</param>
        /// <param name="code">The status code.</param>
        /// <remarks>
        /// The basic status code usage:
        /// negative value - indicates error,
        /// zero value - indicates no status,
        /// positive value - indicates success
        /// </remarks>
        public static void PersistStatus(this TempDataDictionary tempData, int code)
        {
            PersistObject(tempData, "STATUS_CODE", code);
        }

        /// <summary>
        /// Persists the status code in the TempData dictionary.
        /// </summary>
        /// <param name="tempData">The TempData dictionary.</param>
        /// <param name="status">A value indicates, if error occured.</param>
        public static void PersistStatus(this TempDataDictionary tempData, bool status)
        {
            PersistStatus(tempData, status ? 1 : -1);
        }

        #endregion

        #region HttpContext

        /// <summary>
        /// Gets the access context associated with HTTP context.
        /// </summary>
        /// <param name="httpCtx">The HTTP context.</param>
        /// <returns>The access context.</returns>
        public static Service Svc(this HttpContext httpCtx)
        {
            return httpCtx.Items[Service.CTX_KEY] as Service;
        }

        /// <summary>
        /// Gets the access context associated with HTTP context.
        /// </summary>
        /// <param name="httpCtx">The HTTP context.</param>
        /// <returns>The access context.</returns>
        public static Service Svc(this HttpContextBase httpCtx)
        {
            return httpCtx.Items[Service.CTX_KEY] as Service;
        }

        #endregion

        #region Service

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static DateTime UserDate(this Service svc, DateTime val)
        {
            int offset = JDM.Int32(svc.Localization.TimeZone.UtcOffset);
            var cvt = val.ToLocal(offset);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal UserPrice(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.Currency.Rate);
            decimal sys = JDM.Decimal(svc.SystemLocalization.Currency.Rate);
            decimal cvt = MathHelper.Ratio(val, sys, usr);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal UserDataSize(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.InformationUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.InformationUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, sys, usr);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal UserWeight(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.WeightUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.WeightUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, sys, usr);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal UserDimension(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.DimensionUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.DimensionUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, sys, usr);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static DateTime SystemDate(this Service svc, DateTime val)
        {
            int offset = JDM.Int32(svc.Localization.TimeZone.UtcOffset);
            var cvt = val.ToUniversal(offset);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal SystemPrice(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.Currency.Rate);
            decimal sys = JDM.Decimal(svc.SystemLocalization.Currency.Rate);
            decimal cvt = MathHelper.Ratio(val, usr, sys);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal SystemDataSize(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.InformationUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.InformationUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, usr, sys);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal SystemWeight(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.WeightUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.WeightUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, usr, sys);
            return cvt;
        }

        /// <summary>
        /// Converts the value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The converted value.</returns>
        public static decimal SystemDimension(this Service svc, decimal val)
        {
            decimal usr = JDM.Decimal(svc.Localization.DimensionUnit.Ratio);
            decimal sys = JDM.Decimal(svc.SystemLocalization.DimensionUnit.Ratio);
            decimal cvt = MathHelper.Ratio(val, usr, sys);
            return cvt;
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string Date(this Service svc, DateTime val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.DateFormat);
            var cvt = val;
            if(autoConvert)
                cvt = UserDate(svc, cvt);
            return cvt.ToStringByFmt(fmt);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string Time(this Service svc, DateTime val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.TimeFormat);
            var cvt = val;
            if(autoConvert)
                cvt = UserDate(svc, cvt);
            return cvt.ToStringByFmt(fmt);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string DateTime(this Service svc, DateTime val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.DateTimeFormat);
            var cvt = val;
            if(autoConvert)
                cvt = UserDate(svc, cvt);
            return cvt.ToStringByFmt(fmt);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <returns>The string representation.</returns>
        public static string Numeric(this Service svc, decimal val)
        {
            string dec = JDM.String(svc.Localization.Country.NumericFormat.DecimalSeparator);
            string grp = JDM.String(svc.Localization.Country.NumericFormat.GroupSeparator);
            string fmt = JDM.String(svc.Localization.Country.NumericFormat.Format);
            return NumericHelper.ToString(val, dec, grp, fmt);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string Price(this Service svc, decimal val, bool autoConvert = true)
        {
            var cvt = val;
            if(autoConvert)
                cvt = UserPrice(svc, cvt);
            string tmp = Numeric(svc, cvt);
            string fmt = JDM.String(svc.Localization.Currency.PriceFormat);
            return String.Format(fmt, tmp);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string DataSize(this Service svc, decimal val, bool autoConvert = true)
        {
            var cvt = val;
            if(autoConvert)
                cvt = UserDataSize(svc, cvt);
            string fmt = JDM.String(svc.Localization.InformationUnit.ValueFormat);
            string tmp = Numeric(svc, cvt);
            return String.Format(fmt, tmp);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string Weight(this Service svc, decimal val, bool autoConvert = true)
        {
            var cvt = val;
            if(autoConvert)
                cvt = UserWeight(svc, cvt);
            string fmt = JDM.String(svc.Localization.WeightUnit.ValueFormat);
            string tmp = Numeric(svc, cvt);
            return String.Format(fmt, tmp);
        }

        /// <summary>
        /// Returns the string representation of a value. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The value.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The string representation.</returns>
        public static string Dimension(this Service svc, decimal val, bool autoConvert = true)
        {
            var cvt = val;
            if(autoConvert)
                cvt = UserDimension(svc, cvt);
            string fmt = JDM.String(svc.Localization.DimensionUnit.ValueFormat);
            string tmp = Numeric(svc, cvt);
            return String.Format(fmt, tmp);
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static DateTime Date(this Service svc, string val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.DateFormat);
            var cvt = DateHelper.Parse(val, fmt);
            if(autoConvert)
                cvt = SystemDate(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static DateTime Time(this Service svc, string val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.TimeFormat);
            var cvt = DateHelper.Parse(val, fmt);
            if(autoConvert)
                cvt = SystemDate(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static DateTime DateTime(this Service svc, string val, bool autoConvert = true)
        {
            string fmt = JDM.String(svc.Localization.Country.DateTimeFormat);
            var cvt = DateHelper.Parse(val, fmt);
            if(autoConvert)
                cvt = SystemDate(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <returns>The alue.</returns>
        public static decimal Numeric(this Service svc, string val)
        {
            string dec = JDM.String(svc.Localization.Country.NumericFormat.DecimalSeparator);
            string sep = JDM.String(svc.Localization.Country.NumericFormat.GroupSeparator);
            string pat = JDM.String(svc.Localization.Country.NumericFormat.Pattern);
            return NumericHelper.Parse(val, dec, sep, pat);
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static decimal Price(this Service svc, string val, bool autoConvert = true)
        {
            decimal cvt = Numeric(svc, val);
            if(autoConvert)
                cvt = SystemPrice(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static decimal DataSize(this Service svc, string val, bool autoConvert = true)
        {
            decimal cvt = Numeric(svc, val);
            if(autoConvert)
                cvt = SystemDataSize(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static decimal Weight(this Service svc, string val, bool autoConvert = true)
        {
            decimal cvt = Numeric(svc, val);
            if(autoConvert)
                cvt = SystemWeight(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Returns the value from a string representation. 
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="val">The string representation.</param>
        /// <param name="autoConvert">A value indicates whether to convert the value.</param>
        /// <returns>The alue.</returns>
        public static decimal Dimension(this Service svc, string val, bool autoConvert = true)
        {
            decimal cvt = Numeric(svc, val);
            if(autoConvert)
                cvt = SystemDimension(svc, cvt);
            return cvt;
        }

        /// <summary>
        /// Determines if the account associated
        ///  with context is in required role.
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="code">The code of role.</param>
        /// <returns>
        /// true if account is not null and is in role; 
        /// otherwise false.
        /// </returns>
        public static bool InRole(this Service svc, string code)
        {
            if(!svc.IsAuthenticated)
                return false;
            var roles = svc.Account.Roles as IEnumerable<dynamic>;
            return roles.Any(x => JDM.String(x.Code).Equals(code));
        }

        /// <summary>
        /// Determines if the account associated with context 
        /// has the required permission.
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="code">The code of permission.</param>
        /// <returns>
        /// true if account is not null and has the permission; 
        /// otherwise false.
        /// </returns>
        public static bool HasPermission(this Service svc, string code)
        {
            if(!svc.IsAuthenticated)
                return false;
            var permissions = svc.Account.Permissions as IEnumerable<dynamic>;
            return permissions.Any(x => JDM.String(x.Code).Equals(code));
        }

        /// <summary>
        /// Gets the account attribute value.
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="key">The key of attribute.</param>
        /// <returns>
        /// The attribute value if account is not null and 
        /// attribute found; otherwise empty string.
        /// </returns>
        public static string Attribute(this Service svc, string key)
        {
            if(!svc.IsAuthenticated || String.IsNullOrWhiteSpace(key))
                return String.Empty;
            var attributes = svc.Account.Attributes as IEnumerable<dynamic>;
            return attributes.Where(x => JDM.String(x.Key).Equals(key))
                .Select(x => JDM.String(x.Value))
                .SingleOrDefault();
        }

        /// <summary>
        /// Gets the account attribute value as the type T. 
        /// </summary>
        /// <typeparam name="T">The required type to return.</typeparam>
        /// <param name="svc">The service instance.</param>
        /// <param name="key">The key of attribute.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The attribute value as the type T if account is not null 
        /// and attribute found; otherwise the default value.
        /// </returns>
        public static T Attribute<T>(this Service svc, string key, T defaultValue = default(T))
        {
            string val = Attribute(svc, key);
            return StringHelper.ParseAs(val, defaultValue);
        }

        /// <summary>
        /// Gets the framework configuration parameter by key.
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="key">The key.</param>
        /// <returns>The parameter value if parameter found; otherwise empty string.</returns>
        public static string Config(this Service svc, string key)
        {
            if(String.IsNullOrWhiteSpace(key))
                return String.Empty;
            if(!svc.Config.ContainsKey(key))
                return String.Empty;
            return svc.Config[key];
        }

        /// <summary>
        /// Gets the framework configuration parameter 
        /// by key as the type T.
        /// </summary>
        /// <typeparam name="T">The type to return.</typeparam>
        /// <param name="svc">The service instance.</param>
        /// <param name="key">The key.</param>
        /// <param name="defaultValue">The default value.</param>
        /// <returns>
        /// The parameter value as the type T if parameter found; 
        /// otherwise the default value.
        /// </returns>
        public static T Config<T>(this Service svc, string key, T defaultValue = default(T))
        {
            string val = Config(svc, key);
            return StringHelper.ParseAs(val, defaultValue);
        }

        /// <summary>
        /// Gets the language pack entry.
        /// </summary>
        /// <param name="svc">The service instance.</param>
        /// <param name="key">The key.</param>
        /// <returns>The entry.</returns>
        public static string Translate(this Service svc, string key)
        {
            if(String.IsNullOrWhiteSpace(key))
                return key;

            var tmp = key.Split(new[]
            {
                ':'
            }, 2, StringSplitOptions.RemoveEmptyEntries);
            if(tmp.Length != 2)
                return key;

            string packCode = tmp[0];
            string entryKey = tmp[1];
            if(String.IsNullOrWhiteSpace(packCode) ||
                String.IsNullOrWhiteSpace(entryKey))
            {
                return key;
            }

            var pack = svc.LanguagePack(packCode);
            if(pack == null)
                return key;
            if(!pack.ContainsKey(entryKey))
                return key;
            return pack[entryKey];
        }

        #endregion

        #region UrlHelper

        /// <summary>
        /// Gets the content path.
        /// </summary>
        /// <param name="helper">The helper instance.</param>
        /// <param name="fmt">The format.</param>
        /// <param name="args">An array of objects.</param>
        /// <returns>The content path.</returns>
        public static string Content(this UrlHelper helper, string fmt, params object[] args)
        {
            string path = String.Format(fmt, args);
            return helper.Content(path);
        }

        /// <summary>
        /// Generates a fully qualified URL using the specified location.
        /// </summary>
        /// <param name="helper">The helper instance.</param>
        /// <param name="location">The location.</param>
        /// <returns>The fully qualified URL.</returns>
        public static string Action(this UrlHelper helper, Loc location)
        {
            return helper.Action(location.Action, location.Controller, location.Params, location.Protocol, location.Host);
        }

        #endregion

        #region HtmlHelper

        /// <summary>
        /// Invokes the specified child action method using the specified location
        /// and renders the result inline in the parent view.
        /// </summary>
        /// <param name="helper">The helper instance.</param>
        /// <param name="location">The location.</param>
        public static void RenderAction(this HtmlHelper helper, Loc location)
        {
            helper.RenderAction(location.Action, location.Controller, location.Params);
        }

        #endregion
    }
}
